package com.ruoyi.business.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.ruoyi.business.annotations.PrivacyEncrypt;
import com.ruoyi.business.enums.PrivacyTypeEnum;
import com.ruoyi.business.utils.PrivacyUtil;
import com.ruoyi.common.core.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.IOException;
import java.util.Objects;

/**
 * @author Wu Yuwei
 * @Description: 自定义序列化
 * @date 2023/1/4 12:27
 */
@NoArgsConstructor
@AllArgsConstructor
public class PrivacySerializer extends JsonSerializer<String> implements ContextualSerializer {

    // 脱敏类型
    private PrivacyTypeEnum privacyTypeEnum;
    // 前几位不脱敏
    private Integer prefixNoMaskLen;
    // 最后几位不脱敏
    private Integer suffixNoMaskLen;
    // 用什么打码
    private String symbol;

    /**
     * 因为要脱敏的数据都是 String 类型的，所以继承 JsonSerializer 时的类型填 String
     * 重写的 serialize 方法是实现脱敏的核心，根据类型 type 的不同去设置序列化后的值
     * @param origin
     * @param jsonGenerator
     * @param serializerProvider
     * @throws IOException
     */
    @Override
    public void serialize(String origin, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (StringUtils.isNotEmpty(origin) && null!=privacyTypeEnum){
            switch (privacyTypeEnum){
                case CUSTOMER:
                    jsonGenerator.writeString(PrivacyUtil.desValue(origin,prefixNoMaskLen,suffixNoMaskLen,symbol));
                    break;
                case NAME:
                    jsonGenerator.writeString(PrivacyUtil.hideChineseName(origin));
                    break;
                case ID_CARD:
                    jsonGenerator.writeString(PrivacyUtil.hideIDCard(origin));
                    break;
                case PHONE:
                    jsonGenerator.writeString(PrivacyUtil.hidePhone(origin));
                    break;
                case EMAIL:
                    jsonGenerator.writeString(PrivacyUtil.hideEmail(origin));
                    break;
                default:
                    throw new IllegalArgumentException("unknown privacy type enum " + privacyTypeEnum);
            }
        }

    }

    /**
     * 重写的 createContextual 方法就是去读取我们自定义的 PrivacyEncrypt 注解，打造一个上下文的环境
     * @param serializerProvider
     * @param beanProperty
     * @return
     * @throws JsonMappingException
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (null!=beanProperty){
            if (Objects.equals(beanProperty.getType().getRawClass(),String.class)){
                PrivacyEncrypt privacyEncrypt = beanProperty.getAnnotation(PrivacyEncrypt.class);
                if (null == privacyEncrypt){
                    privacyEncrypt = beanProperty.getContextAnnotation(PrivacyEncrypt.class);
                }
                if (null != privacyEncrypt){
                    return new PrivacySerializer(privacyEncrypt.type(),
                            privacyEncrypt.prefixNoMaskLen(),
                            privacyEncrypt.suffixNoMaskLen(),
                            privacyEncrypt.symbol());
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(),beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }
}
